﻿using System;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Windows;
using System.Windows.Navigation;
using BingleMaps.ViewModels;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;

namespace BingleMaps
{
	public partial class App
	{
		// Easy access to the root frame
		private PhoneApplicationFrame RootFrame { get; set; }

		// Constructor
		public App()
		{
			// Global handler for uncaught exceptions. 
			// Note that exceptions thrown by ApplicationBarItem.Click will not get caught here.
			UnhandledException += ApplicationUnhandledException;

			// Standard Silverlight initialization
			InitializeComponent();

			// Phone-specific initialization
			InitializePhoneApplication();

			// Load configuration and resources.
			Globals.DefaultZoomLevel = (double)Resources["DefaultZoomLevel"];
			Globals.PinDragFloatOffsetY = (double)Resources["PinDragFloatOffsetY"];
			Globals.BackwardCompatibleVersion = new Version(Resources["BackwardCompatibleVersion"].ToString());

			// Update network changes.
			Globals.IsNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();
			NetworkChange.NetworkAddressChanged += (s, e) => Globals.IsNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();

			// Limit max frame rate to 30 for better overall graphical performance.
			Host.Settings.MaxFrameRate = 30;

#if DEBUG
			if (Debugger.IsAttached)
			{
				//Host.Settings.EnableRedrawRegions = true;
			}
#endif
		}

		// Code to execute when the application is launching (eg, from Start)
		// This code will not execute when the application is reactivated
		private void ApplicationLaunching(object sender, LaunchingEventArgs e)
		{
			ViewModelLocator.MainStatic.Wake(NotifyOldSaveData);
		}

		private void NotifyOldSaveData(Version saveVersion)
		{
			MessageBox.Show("The data saved on your phone is from an incompetible old version. It can not be loaded into this version of the application.", "Incompatible Save Data", MessageBoxButton.OK);
		}

		// Code to execute when the application is activated (brought to foreground)
		// This code will not execute when the application is first launched
		private void ApplicationActivated(object sender, ActivatedEventArgs e)
		{
			if (e.IsApplicationInstancePreserved)
			{
				return;
			}
			ViewModelLocator.MainStatic.Wake(NotifyOldSaveData);
		}

		// Code to execute when the application is deactivated (sent to background)
		// This code will not execute when the application is closing
		private void ApplicationDeactivated(object sender, DeactivatedEventArgs e)
		{
			ViewModelLocator.MainStatic.Sleep();
		}

		// Code to execute when the application is closing (eg, user hit Back)
		// This code will not execute when the application is deactivated
		private void ApplicationClosing(object sender, ClosingEventArgs e)
		{
			ViewModelLocator.MainStatic.Sleep();
			ViewModelLocator.Cleanup();
		}

		// Code to execute if a navigation fails
		private static void RootFrameNavigationFailed(object sender, NavigationFailedEventArgs e)
		{
			if (Debugger.IsAttached)
			{
				// A navigation has failed; break into the debugger
				Debugger.Break();
			}
		}

		// Code to execute on Unhandled Exceptions
		private void ApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
		{
			e.Handled = !Debugger.IsAttached;
			if (e.ExceptionObject is InvalidOperationException && e.ExceptionObject.Message == "No Fragment support right now")
			{
				return;
			}
			if (e.ExceptionObject.GetType().ToString() == "MS.Internal.WrappedException")
			{
				return;
			}
			switch (e.ExceptionObject.Message)
			{
				case "0x8000ffff":
				case "Unspecified error ":
					return;
			}
			if (Debugger.IsAttached)
			{
				// An unhandled exception has occurred; break into the debugger
				Debugger.Break();
			}
			else if (MessageBox.Show("The application has encountered an error, we apologize for any inconvenience." + Environment.NewLine + Environment.NewLine + "Do you want to report this error via email?", "Oops...", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
			{
				new EmailComposeTask
				{
					Body =
						"Running on: " + Microsoft.Devices.Environment.DeviceType + Environment.NewLine + Environment.NewLine +
						"App: " + Assembly.GetExecutingAssembly().FullName + Environment.NewLine + Environment.NewLine +
						"OS: " + Environment.OSVersion + Environment.NewLine + Environment.NewLine +
						"CLR: " + Environment.Version + Environment.NewLine + Environment.NewLine +
						"Silverlight: " + Deployment.Current.RuntimeVersion + Environment.NewLine + Environment.NewLine +
						"Location: " + RootFrame.CurrentSource + Environment.NewLine + Environment.NewLine +
						"Message: " + e.ExceptionObject.Message + Environment.NewLine + Environment.NewLine +
						"Trace:" + Environment.NewLine + e.ExceptionObject.StackTrace,
					Subject = e.ExceptionObject.GetType().ToString(),
					To = Resources["Email"].ToString()
				}.Show();
			}
		}

		#region Phone application initialization

		// Avoid double-initialization
		private bool _phoneApplicationInitialized;

		// Do not add any additional code to this method
		private void InitializePhoneApplication()
		{
			if (_phoneApplicationInitialized)
			{
				return;
			}

			// Create the frame but don't set it as RootVisual yet; this allows the splash
			// screen to remain active until the application is ready to render.
			RootFrame = new TransitionFrame();
			RootFrame.Navigated += CompleteInitializePhoneApplication;

			// Handle navigation failures
			RootFrame.NavigationFailed += RootFrameNavigationFailed;

			// Ensure we don't initialize again
			_phoneApplicationInitialized = true;
		}

		// Do not add any additional code to this method
		private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
		{
			// Set the root visual to allow the application to render
			RootVisual = RootFrame;

			// Remove this handler since it is no longer needed
			RootFrame.Navigated -= CompleteInitializePhoneApplication;
		}

		#endregion
	}
}
